<?php

namespace addons\oss\library;

use OSS\Core\OssException;
use OSS\OssClient;
use think\Cache;

/**
 * Token
 */

final class Util
{
    private $accessKeyId;
    private $accessKeySecret;
    private $endPoint;
    private $cdnUrl;
    private $dir;
    private $bucket;
    private $maxsize;
    private $mimetype;
    private $expire;
    private $savekey;
    private $vpc;
    private $vpc_endpoint;

    public function __construct($config = [])
    {
        $this->accessKeyId = $config['accessKeyId'];
        $this->accessKeySecret = $config['accessKeySecret'];
        $this->endPoint = $config['endpoint'];
        $this->cdnUrl = $config['cdnurl'];
        $this->bucket = $config['bucket'];
        $this->dir = preg_replace("/^\/*/", "", $config['dir']);
        $this->maxsize = empty($config['maxsize']) ? 4*1024*1024 : $config['maxsize'];
        $this->mimetype = $config['mimetype'];
        $this->savekey = isset($config['savekey']) ? $config['savekey'] : "";
        $this->expire = isset($config['expire']) ? $config['expire'] : 120;
        $this->vpc = isset($config['vpc']) && !empty($config['vpc'])? true : false;

        $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
        preg_match('/(\d+)(\w+)/',$this->maxsize, $matches);
        $size_base = isset($matches[1]) ? $matches[1] : 4;
        $type = isset($matches[2]) ? strtolower($matches[2]) : "";
        $size = $size_base * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
    }  


    public function getToken($force_update = false)
    {

    	if(!$force_update)
    	{
    		$cache = Cache::get("ADDONS_OSS_TOKEN");
	    	if( $cache )
	    		return $cache;
    	}    	

    	$now = time();
	    $end = $now + $this->expire;
	    $expiration = self::gmt_iso8601($end);

	    //最大文件大小.用户可以自己设置
	    $conditions[] = array(0=>'content-length-range', 1=>0, 2=>$this->maxsize); 

		//表示用户上传的数据,必须是以$dir开始, 不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录
		if( !empty($this->dir) )
		{ 
	    	$conditions[] = array(0=>'starts-with', 1=>'$key', 2=>$this->dir);
		}

	    $policy = json_encode(array('expiration'=>$expiration,'conditions'=>$conditions));
	    $base64_policy = base64_encode($policy);
	    $signature = base64_encode(hash_hmac('sha1', $base64_policy, $this->accessKeySecret, true));

	    // exit( $policy );

	    $response = array();
	    $response['accessid'] = $this->accessKeyId;
	    $response['host'] = "http://{$this->bucket}.{$this->endPoint}";
	    $response['policy'] = $base64_policy;
	    $response['signature'] = $signature;
	    $response['expire'] = $end;
	    $response['savekey'] = $this->savekey;
	    //这个参数是设置用户上传指定的前缀
	    $response['dir'] = $this->dir;
	    $response['cdnurl'] = $this->cdnUrl;

	    Cache::set("ADDONS_OSS_TOKEN", $response, $this->expire - 30 );
	    return $response;
    }

    public function saveToOss($lcoal_file)
    {
    	if( $this->vpc && !$this->vpc_endpoint)
    	{
    		$this->vpc_endpoint = str_replace(".aliyuncs.com", "-internal.aliyuncs.com", $this->endPoint);
    	}

    	// var_dump($this->vpc_endpoint);exit();

    	// 创建客户端
        $client = new OssClient($this->accessKeyId,$this->accessKeySecret,$this->vpc_endpoint ? $this->vpc_endpoint : $this->endPoint);

        // 设置请求超时时间，单位：秒
        $client->setTimeout(30);
        // 设置连接超时时间，单位：秒
        $client->setConnectTimeout(30);

        // 上传文件
        try
        {
            // 执行文件上传操作
            $result = $client->uploadFile($this->bucket, $this->getObjName($lcoal_file) , $lcoal_file);

            // 返回上传成功后的URL

            return $this->getObjUrl($result['oss-request-url']);
        }
        catch(OssException $exception)
        {
            throw new \Exception($exception->getMessage());
        }
    }

    public function delFormOss($lcoal_file)
    {
    	if( $this->vpc && !$this->vpc_endpoint)
    	{
    		$this->vpc_endpoint = str_replace(".aliyuncs.com", "-internal.aliyuncs.com", $this->endPoint);
    	}

    	// var_dump($this->vpc_endpoint);exit();

    	// 创建客户端
        $client = new OssClient($this->accessKeyId,$this->accessKeySecret,$this->vpc_endpoint ? $this->vpc_endpoint : $this->endPoint);

        // 设置请求超时时间，单位：秒
        $client->setTimeout(30);
        // 设置连接超时时间，单位：秒
        $client->setConnectTimeout(30);

        try
        {
            // 执行文件删除操作
            $result = $client->deleteObject($this->bucket, $this->getObjName($lcoal_file) );
            return $result;
        }
        catch(OssException $exception)
        {
            throw new \Exception($exception->getMessage());
        }    	
    }

    public function getObjName($lcoal_file)
    {     
        return $this->dir.str_replace(ROOT_PATH . 'public/', "", $lcoal_file);
    }

    public function createObjName($lcoal_file)
    {
    	$suffix = substr($lcoal_file, stripos($lcoal_file, '.') + 1);
    	$md5 = md5_file($lcoal_file);
    	if(!empty($this->savekey))
    	{
    		$name = basename($lcoal_file);       		
	        $search = ['{year}', '{mon}', '{month}', '{day}', '{filemd5}', '{suffix}', '{.suffix}'];
	        $replace = [date("Y"), date("m"), date("m"), date("d"), $md5, $suffix, '.' . $suffix];
	        $filename = ltrim(str_replace($search, $replace, $this->savekey), '/');
    	}else{
    		$filename = $md5.".".$suffix;
    	}        
        return $this->dir.$filename;
    }

    public function getObjUrl($filename)
    {
    	$filename = preg_replace("/(http[s]?\:\/\/[^\/]*\/)/", "", $filename);

    	if( !empty($this->cdnUrl) )
    	{    		
    		return preg_match("/.*?\/$/", $this->cdnUrl) ? $this->cdnUrl.$filename : $this->cdnUrl."/".$filename;
    	}

    	$host = preg_match("/^https?.*/", $this->endPoint) ? $this->endPoint: "https://".$this->bucket.".".$this->endPoint;

    	return preg_match("/.*?\/$/", $host) ? $host.$filename : $host."/".$filename;
    }

    protected static function gmt_iso8601($time) 
    {
        $dtStr = date("c", $time);
        $mydatetime = new \DateTime($dtStr);
        $expiration = $mydatetime->format(\DateTime::ISO8601);
        $pos = strpos($expiration, '+');
        $expiration = substr($expiration, 0, $pos);
        return $expiration."Z";
    }

}

 
